package org.stock.agent.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.ai.retry.TransientAiException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.stock.agent.model.AnalysisResult;
import org.stock.agent.model.ComprehensiveAnalysis;


import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class ChiefAnalyst {

    private final ChatClient openAiChatClient;
    private final ChatModel chatModel;

    @Autowired
    private TechnicalAnalyst technicalAnalyst;

    @Autowired
    private FundamentalAnalyst fundamentalAnalyst;

    @Autowired
    private SentimentAnalyst sentimentAnalyst;

    @Autowired
    private ValuationAnalyst valuationAnalyst;
    
    @Autowired
    private IndustryAnalyst industryAnalyst;

    public ChiefAnalyst(ChatModel chatModel) {
        this.chatModel = chatModel;

        this.openAiChatClient = ChatClient.builder(chatModel)
                .defaultAdvisors(
                        MessageChatMemoryAdvisor.builder(MessageWindowChatMemory.builder().build()).build()
                )
                .defaultAdvisors(
                        new SimpleLoggerAdvisor()
                )
                .defaultOptions(
                        OpenAiChatOptions.builder()
                                .topP(0.7)
                                .build()
                )
                .build();
    }

    public ComprehensiveAnalysis analyzeStock(String symbol) {
        // 顺序调用各分析角色，增加重试机制
        AnalysisResult technicalAnalysis = retryWithBackoff(() -> technicalAnalyst.analyzeTechnical(symbol));
        AnalysisResult fundamentalAnalysis = retryWithBackoff(() -> fundamentalAnalyst.analyzeFundamental(symbol));
        AnalysisResult sentimentAnalysis = retryWithBackoff(() -> sentimentAnalyst.analyzeSentiment(symbol));
        AnalysisResult valuationAnalysis = retryWithBackoff(() -> valuationAnalyst.analyzeValuation(symbol));
        AnalysisResult industryAnalysis = retryWithBackoff(() -> industryAnalyst.analyzeIndustry(symbol));

        List<AnalysisResult> allAnalyses = List.of(technicalAnalysis, fundamentalAnalysis, sentimentAnalysis, valuationAnalysis, industryAnalysis);

        // 构造综合分析报告
        ComprehensiveAnalysis comprehensiveAnalysis = new ComprehensiveAnalysis();
        comprehensiveAnalysis.setSymbol(symbol);
        comprehensiveAnalysis.setTimestamp(LocalDateTime.now().toString());

        // 计算综合概率
        double overallProbability = allAnalyses.stream()
                .mapToDouble(a -> Double.parseDouble(a.getProbability()))
                .average()
                .orElse(0.0);
        comprehensiveAnalysis.setOverallProbability(String.format("%.2f", overallProbability));

        // 各角色分析概率
        Map<String, String> roleProbabilities = new HashMap<>();
        roleProbabilities.put("价值投资技术分析师", technicalAnalysis.getProbability());
        roleProbabilities.put("价值投资基本面分析师", fundamentalAnalysis.getProbability());
        roleProbabilities.put("价值投资情绪分析师", sentimentAnalysis.getProbability());
        roleProbabilities.put("价值投资估值分析师", valuationAnalysis.getProbability());
        roleProbabilities.put("价值投资行业分析师", industryAnalysis.getProbability());
        comprehensiveAnalysis.setRoleProbabilities(roleProbabilities);

        // 使用AI生成投资建议
        String investmentAdvicePrompt = buildInvestmentAdvicePrompt(allAnalyses, overallProbability);
        String response = openAiChatClient.prompt()
                .user(investmentAdvicePrompt)
                .call()
                .content();
        comprehensiveAnalysis.setInvestmentRecommendation(response);

        // 使用AI生成详细理由
        String detailedReasoningPrompt = buildDetailedReasoningPrompt(allAnalyses);
        response = openAiChatClient.prompt()
                .user(detailedReasoningPrompt)
                .call()
                .content();
        comprehensiveAnalysis.setDetailedReasoning(response);

        // 使用AI生成关键支撑因素
        String keySupportingFactorsPrompt = buildKeySupportingFactorsPrompt(allAnalyses);
        response = openAiChatClient.prompt()
                .user(keySupportingFactorsPrompt)
                .call()
                .content();
        comprehensiveAnalysis.setKeySupportingFactors(response);

        // 使用AI生成主要风险
        String mainRisksPrompt = buildMainRisksPrompt(allAnalyses);
        response = openAiChatClient.prompt()
                .user(mainRisksPrompt)
                .call()
                .content();
        comprehensiveAnalysis.setMainRisks(response);

        // 使用AI生成关注事件
        String keyEventsToWatchPrompt = buildKeyEventsToWatchPrompt(allAnalyses);
        response = openAiChatClient.prompt()
                .user(keyEventsToWatchPrompt)
                .call()
                .content();
        comprehensiveAnalysis.setKeyEventsToWatch(response);

        return comprehensiveAnalysis;
    }

    /**
     * 构建投资建议提示词
     */
    private String buildInvestmentAdvicePrompt(List<AnalysisResult> allAnalyses, double overallProbability) {
        StringBuilder prompt = new StringBuilder();
        prompt.append("你是一位经验丰富的首席股票分析师，请根据以下各维度的分析结果，给出一个综合的投资建议：\n\n");
        
        for (AnalysisResult analysis : allAnalyses) {
            prompt.append(analysis.getAnalystRole())
                  .append("分析结果：\n")
                  .append("适合作为价值投资标的的概率：").append(String.format("%.1f", Double.parseDouble(analysis.getProbability()))).append("%\n")
                  .append("分析理由：").append(analysis.getReasoning()).append("\n")
                  .append("置信度：").append(analysis.getConfidenceLevel()).append("\n\n");
        }
        
        prompt.append("综合概率为：").append(String.format("%.1f", overallProbability)).append("%\n\n");
        prompt.append("请根据以上信息，给出一个明确的投资建议，包括：\n");
        prompt.append("1. 是否建议投资这只股票\n");
        prompt.append("2. 如果建议投资，建议的仓位大小\n");
        prompt.append("3. 如果不建议投资，说明原因\n");
        prompt.append("4. 投资的时间周期建议\n");
        prompt.append("请用中文回答，内容要具体明确，避免模棱两可的表述。");
        
        return prompt.toString();
    }

    /**
     * 构建详细理由提示词
     */
    private String buildDetailedReasoningPrompt(List<AnalysisResult> allAnalyses) {
        StringBuilder prompt = new StringBuilder();
        prompt.append("你是一位经验丰富的首席股票分析师，请根据以下各维度的分析结果，给出一个综合的详细分析理由：\n\n");
        
        for (AnalysisResult analysis : allAnalyses) {
            prompt.append(analysis.getAnalystRole())
                  .append("分析结果：\n")
                  .append("适合作为价值投资标的的概率：").append(String.format("%.1f", Double.parseDouble(analysis.getProbability()))).append("%\n")
                  .append("分析理由：").append(analysis.getReasoning()).append("\n")
                  .append("置信度：").append(analysis.getConfidenceLevel()).append("\n\n");
        }
        
        prompt.append("请综合以上所有分析维度，给出一个全面、深入的分析理由，解释为什么得出这样的综合结论。\n");
        prompt.append("要求：\n");
        prompt.append("1. 分析需要逻辑清晰，有条理\n");
        prompt.append("2. 需要权衡各个维度的分析结果\n");
        prompt.append("3. 对于相互矛盾的分析观点，需要给出你的判断和理由\n");
        prompt.append("4. 用中文回答，内容详实但不冗长");
        
        return prompt.toString();
    }

    /**
     * 构建关键支撑因素提示词
     */
    private String buildKeySupportingFactorsPrompt(List<AnalysisResult> allAnalyses) {
        StringBuilder prompt = new StringBuilder();
        prompt.append("你是一位经验丰富的首席股票分析师，请根据以下各维度的分析结果，总结出关键的支撑因素：\n\n");
        
        for (AnalysisResult analysis : allAnalyses) {
            prompt.append(analysis.getAnalystRole())
                  .append("分析结果：\n")
                  .append("适合作为价值投资标的的概率：").append(String.format("%.1f", Double.parseDouble(analysis.getProbability()))).append("%\n")
                  .append("分析理由：").append(analysis.getReasoning()).append("\n")
                  .append("置信度：").append(analysis.getConfidenceLevel()).append("\n\n");
        }
        
        prompt.append("请总结出3-5个关键的支撑因素，这些因素支持将该股票作为价值投资标的。\n");
        prompt.append("要求：\n");
        prompt.append("1. 每个因素需要具体明确\n");
        prompt.append("2. 尽量选择各分析维度中共同支持的因素\n");
        prompt.append("3. 用中文回答，每个因素单独列出");
        
        return prompt.toString();
    }

    /**
     * 构建主要风险提示词
     */
    private String buildMainRisksPrompt(List<AnalysisResult> allAnalyses) {
        StringBuilder prompt = new StringBuilder();
        prompt.append("你是一位经验丰富的首席股票分析师，请根据以下各维度的分析结果，总结出主要的风险因素：\n\n");
        
        for (AnalysisResult analysis : allAnalyses) {
            prompt.append(analysis.getAnalystRole())
                  .append("分析结果：\n")
                  .append("适合作为价值投资标的的概率：").append(String.format("%.1f", Double.parseDouble(analysis.getProbability()))).append("%\n")
                  .append("分析理由：").append(analysis.getReasoning()).append("\n")
                  .append("置信度：").append(analysis.getConfidenceLevel()).append("\n\n");
        }
        
        prompt.append("请总结出3-5个主要的风险因素，这些因素可能影响该股票的投资价值。\n");
        prompt.append("要求：\n");
        prompt.append("1. 每个风险需要具体明确\n");
        prompt.append("2. 优先考虑各分析维度中指出的风险\n");
        prompt.append("3. 用中文回答，每个风险单独列出");
        
        return prompt.toString();
    }

    /**
     * 构建关注事件提示词
     */
    private String buildKeyEventsToWatchPrompt(List<AnalysisResult> allAnalyses) {
        StringBuilder prompt = new StringBuilder();
        prompt.append("你是一位经验丰富的首席股票分析师，请根据以下各维度的分析结果，列出需要关注的关键事件：\n\n");
        
        for (AnalysisResult analysis : allAnalyses) {
            prompt.append(analysis.getAnalystRole())
                  .append("分析结果：\n")
                  .append("适合作为价值投资标的的概率：").append(String.format("%.1f", Double.parseDouble(analysis.getProbability()))).append("%\n")
                  .append("分析理由：").append(analysis.getReasoning()).append("\n")
                  .append("置信度：").append(analysis.getConfidenceLevel()).append("\n\n");
        }
        
        prompt.append("请列出5-8个需要持续关注的关键事件或指标变化，这些事件可能会影响投资决策。\n");
        prompt.append("要求：\n");
        prompt.append("1. 事件需要具体可观察\n");
        prompt.append("2. 包括短期和长期需要关注的事件\n");
        prompt.append("3. 用中文回答，每个事件单独列出");
        
        return prompt.toString();
    }

    /**
     * 带有指数退避的重试机制
     */
    private AnalysisResult retryWithBackoff(java.util.function.Supplier<AnalysisResult> operation) {
        int maxRetries = 5; // 增加重试次数
        long baseDelay = 2; // 基础延迟时间（秒）
        
        for (int i = 0; i < maxRetries; i++) {
            try {
                return operation.get();
            } catch (TransientAiException e) {
                log.warn("AI服务暂时不可用，重试次数: {}/{}，错误信息: {}", i+1, maxRetries, e.getMessage());
                
                if (i == maxRetries - 1) {
                    // 最后一次重试仍然失败
                    log.error("AI服务重试{}次后仍然失败，返回默认分析结果", maxRetries);
                    break;
                }
                
                try {
                    // 指数退避延迟 + 随机抖动
                    long delay = (long) (baseDelay * Math.pow(2, i) + Math.random() * baseDelay);
                    log.info("等待{}秒后进行第{}次重试", delay, i+2);
                    TimeUnit.SECONDS.sleep(delay);
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                    throw new RuntimeException("重试过程中线程被中断", ie);
                }
            } catch (Exception e) {
                log.error("分析过程中发生未预期的错误", e);
                break; // 非临时性错误直接退出
            }
        }
        
        // 返回默认的分析结果
        AnalysisResult defaultResult = new AnalysisResult();
        defaultResult.setAnalystRole("默认分析师");
        defaultResult.setProbability("50.0");
        defaultResult.setReasoning("由于AI服务暂时不可用，无法获取完整的分析结果。这是基于有限信息的默认评估。建议稍后重试。");
        defaultResult.setConfidenceLevel("低");
        return defaultResult;
    }

    private String extractMainReason(String reasoning) {
        if (reasoning == null || reasoning.isEmpty()) {
            return "未提供具体原因";
        }
        // 简单提取前50个字符作为主要原因
        int endIndex = Math.min(50, reasoning.length());
        return reasoning.substring(0, endIndex) + (reasoning.length() > 50 ? "..." : "");
    }
}